package com.lecture.java8.date;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author luyn
 * @version 1.0
 * @description 合并时间区间
 * @date 2021/5/29 13:28
 */
public class UnionTimeProcAlgorithm {

    public static void main(String[] args) {
        Map<String,String> map1 = new HashMap<>();
        map1.put("startTime","2020-07-14 00:00:00");
        map1.put("endTime","2020-07-15 00:00:00");

        Map<String,String> map2 = new HashMap<>();
        map2.put("startTime","2020-07-18 00:00:00");
        map2.put("endTime","2020-07-19 00:00:00");

        Map<String,String> map3 = new HashMap<>();
        map3.put("startTime","2020-07-16 00:00:00");
        map3.put("endTime","2020-07-19 00:00:00");

        Map<String,String> map4 = new HashMap<>();
        map4.put("startTime","2020-07-22 00:00:00");
        map4.put("endTime","2020-07-24 00:00:00");

        List<Map<String, String>> list = new ArrayList<>();
        list.add(map1);
        list.add(map2);
        list.add(map3);
        list.add(map4);

        UnionTimeProcAlgorithm un = new UnionTimeProcAlgorithm();
        List<Map<String,String>> calc = un.calc(list.toArray(new Map[list.size()]));
        for (Map<String, String> map : calc) {
            System.out.println(map.get("startTime") + "  " + map.get("endTime"));
        }
    }

    public List<Map<String, String>> calc(Map<String, String>[] param) {
        List<Map<String, String>> value = new ArrayList<>();
        Map<String, String>[] timeProcs = check(param);
        if (timeProcs == null || timeProcs.length == 0) {
            return Collections.emptyList();
        }
        value.add(timeProcs[0]);
        for (int i = 1; i < timeProcs.length; i++) {
            //判断该区间的左端点在value中的位置
            int[] leftPositon = getPosition(value, 0, getDateTime(timeProcs[i].get("startTime")));
            if (leftPositon[0] == 1) {
                //1左端属于value的情况
                int[] rightPosition = getPosition(value, leftPositon[1], getDateTime(timeProcs[i].get("endTime")));
                if (rightPosition[0] == 1) {
                    //右端也属于value
                    if (leftPositon[1] == rightPosition[1]) {
                        continue;
                    }
                    value.get(leftPositon[1]).put("endTme", value.get(rightPosition[1]).get("endTime"));
                    for (int j = leftPositon[1]+1; j < rightPosition[1]; j++) {
                        value.remove(j);
                    }
                } else {
                    //2右端点不属于value
                    value.get(leftPositon[i]).put("endTime", timeProcs[i].get("endTime"));
                    for (int j = leftPositon[1]+1; j < rightPosition[1]; j++) {
                        value.remove(j);
                    }
                }
            } else {
                value.add(leftPositon[1], timeProcs[i]);
                refresh(value, leftPositon[1]);
            }
        }
        return value;
    }

    public void refresh(List<Map<String, String>> value, int index) {
        Map<String, String> temp = value.get(index);
        int[] indexRightPosition = getPosition(value, index+1,getDateTime(temp.get("endTime")));
        if (indexRightPosition[0] == 1) {
            Map<String, String> includeRight = value.get(indexRightPosition[1]);
            temp.put("endTime", includeRight.get("endTime"));
            for (int i = index+1; i <= indexRightPosition[1]; i++) {
                value.remove(i);
            }
        } else if (indexRightPosition[0] == 0) {
            //删除该区间内所有区间
            for (int i = index+1; i < indexRightPosition[1]; i++) {
                value.remove(i);
            }
        }
    }

    public int[] getPosition(List<Map<String, String>> value, int from, Long point) {
        if (from >= value.size()) {
            return new int[]{0, value.size()};
        }
        if (point < getDateTime(value.get(from).get("startTime"))) {
            return new int[]{0, from};
        }

        for (int i = from; i < value.size()-1; i++) {
            Map<String, String> tmp = value.get(i);
            if (isContain(tmp, point)) {
                return new int[]{1, i};
            }
            Map<String, String> tmpLater = value.get(i+1);
            if (point > getDateTime(tmp.get("endTime")) && point < getDateTime(tmpLater.get("startTime"))) {
                return new int[]{0, i+1};
            }
        }
        //比较最后一个区间
        Map<String, String> last = value.get(value.size() - 1);
        if (isContain(last, point)) {
            return new int[]{1, value.size() - 1};
        } else {
            return new int[]{0, value.size()};
        }
    }

    //数组检查 数组元素左边的树不得小于右边的元素
    public Map<String, String>[] check(Map<String, String>[] temp) {
        //不破坏原来的数据
        Map<String, String>[] timeProcs = new HashMap[temp.length];
        for (int i = 0; i < timeProcs.length; i++) {
            Map<String, String> map = new HashMap<>();
            map.put("startTime", temp[i].get("startTime"));
            map.put("endTime", temp[i].get("endTime"));
            timeProcs[i] = map;
        }

        int length = timeProcs.length;
        for (int i = 0; i < timeProcs.length; i++) {
            if (getDateTime(timeProcs[i].get("endTime")) < getDateTime(timeProcs[i].get("startTime"))) {
                timeProcs[i] = null;
                length--;
            }
        }

        Map<String,String>[] result = new Map[length];
        int index = 0;
        for (int i = 0; i < timeProcs.length; i++) {
            if (timeProcs[i] != null) {
                result[index] = timeProcs[i];
                index++;
            }
        }
        return result;
    }

    public boolean isContain(Map<String, String> map, Long startTime) {
        return startTime <= getDateTime(map.get("endTime")) && startTime >= getDateTime(map.get("startTime"));
    }

    public Long getDateTime(String date) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return sdf.parse(date).getTime();
        } catch (Exception e) {
            return null;
        }
    }
}
